package com.globallogic.javatrainings.sergiiivanov.tests;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import org.junit.Before;
import org.junit.Test;

import com.globallogic.javatrainings.sergiiivanov.model.Const.Discipline;
import com.globallogic.javatrainings.sergiiivanov.model.*;
import com.globallogic.javatrainings.sergiiivanov.model.Lecture.LectureType;
import com.globallogic.javatrainings.sergiiivanov.resources.ErrorCodes;

/**
 * <pre>26  4.    Courses
27  4.1.  Course has name, Discipline and linked to specific teacher
28  4.2.  Course name should be unique within one university
29  4.3.  Course contains of Lectures
30  4.4.  Courses list should be available
31  4.5.  Course relevant scores table should be available</pre>
 * @author Sergey
 *
 */
public class CourseTest extends BasicTest{

    private Teacher teacher;
    private Course course;
    
    @Before
    public void courseCreationAndMembersTest() throws Exception {
        u = new University(nUniversity);
        course = new Course();
        course.setName(nCourse1);
        course.setDiscipline(discipline1);
        teacher = new Teacher(nPerson1, mobile, email);
        course.setTeacher(teacher);
        assertEquals(nCourse1, course.getName());
        assertEquals(discipline1, course.getDiscipline());
        assertEquals(teacher, course.getTeacher());
    }

    @Test
    public void nameNotEmptyTest(){
        try {
            course.setName(empty);            
            fail("Missed " + ErrorCodes.COURSE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NAME_NULL, e.getMessage());
        }
        try {
            course.setName(null);            
            fail("Missed " + ErrorCodes.COURSE_NAME_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NAME_NULL, e.getMessage());
        }
    }
    
    @Test
    public void nameUniqueTest() throws Exception {
        u.courses.addCource(nCourse1, discipline1);
        u.courses.getCourseByIndex(0).setName(nCourse1);
        try {
            u.courses.addCource(nCourse1, discipline2);
            fail("Missed " + ErrorCodes.COURSE_NAME_NOT_UNIQUE);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NAME_NOT_UNIQUE+nCourse1, e.getMessage());
        }
    }
    
    @Test
    public void enrollDisenrollTest() throws Exception {
        assertArrayEquals(new Student[] {}, course.getEnrolledStudents().toArray());
        Student s1 = new Student(nPerson1, mobile, email);
        Student s2 = new Student(nPerson1, mobile, email);
        course.enrollStudent(s1);
        try {
            course.enrollStudent(s1);
            fail("Missed " + ErrorCodes.STUDENT_ALREADY_ENROLLED+s1.getName());
        } catch (Exception e) {
            assertEquals(ErrorCodes.STUDENT_ALREADY_ENROLLED+s1.getName(), e.getMessage());
        }
        course.enrollStudent(s2);
        assertArrayEquals(new Student[] {s1,s2}, course.getEnrolledStudents().toArray());
        assertEquals(2, course.countStudents());
        course.disenrollStudent(s1);
        try {
            course.disenrollStudent(s1);
            fail("Missed " + ErrorCodes.STUDENT_NOT_ENROLLED_TO+course.getName());
        } catch (Exception e) {
            assertEquals(ErrorCodes.STUDENT_NOT_ENROLLED_TO+course.getName(), e.getMessage());
        }
        course.disenrollStudent(s2);
        assertArrayEquals(new Student[] {}, course.getEnrolledStudents().toArray());
        assertEquals(0, course.countStudents());
    }

    @Test
    public void scoresTest() throws UniversityWarning, UniversityFailure {
        Course c = simpleCourse();
        Student s1 = new Student(nPerson1, mobile, email);
        c.enrollStudent(s1);
        try {
            s1.addScore(c.getLectureByIndex(0), Const.MIN_SCORE, "");
            fail("Missed " + ErrorCodes.SCORE_NO_TEACHER);
        } catch (Exception e) {
            assertEquals(ErrorCodes.SCORE_NO_TEACHER, e.getMessage());
        }
        c.setTeacher(new Teacher("t", "", ""));
        s1.addScore(c.getLectureByIndex(0), Const.MIN_SCORE, "");
        try {
            c.setDiscipline(Discipline.Java7);
            fail("Missed " + ErrorCodes.COURSE_HAVE_SCORES_CANT_CHANGE_DISCIPLINE);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_HAVE_SCORES_CANT_CHANGE_DISCIPLINE, e.getMessage());
        }
        try {
            s1.addScore(null, Const.MIN_SCORE, "");
            fail("Missed " + ErrorCodes.SCORE_COURSE_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.SCORE_COURSE_NULL, e.getMessage());
        }
        try {
            s1.addScore(null, 50, "");
            fail("Missed " + ErrorCodes.SCORE_COURSE_NULL);
        } catch (Exception e) {
            assertEquals(ErrorCodes.SCORE_COURSE_NULL, e.getMessage());
        }
        try {
            s1.addScore(simpleCourse().getLectureByIndex(0), Const.MIN_SCORE, "");
            fail("Missed " + ErrorCodes.STUDENT_NOT_ENROLLED_TO);
        } catch (Exception e) {
            assertEquals(ErrorCodes.STUDENT_NOT_ENROLLED_TO + c.getName(), e.getMessage());
        }

        try {
            s1.addScore(c.getLectureByIndex(0), Const.MAX_SCORE + 1, "");
            fail("Missed " + ErrorCodes.SCORE_WRONG_VALUE);
        } catch (Exception e) {
            assertEquals(ErrorCodes.SCORE_WRONG_VALUE, e.getMessage());
        }
        int invalidScore = Const.MIN_SCORE - 1;
        try {
            s1.addScore(c.getLectureByIndex(0), invalidScore, "");
            fail("Missed " + ErrorCodes.SCORE_WRONG_VALUE);
        } catch (Exception e) {
            assertEquals(ErrorCodes.SCORE_WRONG_VALUE, e.getMessage());
        }
    }

    private Course simpleCourse() throws UniversityWarning {
        Course c = new Course();
        c.setName("course");
        c.setDiscipline(Discipline.Cpp);
        c.addLecture("Lecture", LectureType.LECTURE, "");
        c.addLecture("test", LectureType.TEST, "");
        c.addLecture("Practice", LectureType.PRACTICE, "");
        c.addLecture("Exam", LectureType.EXAMINATION, "");
        return c;
    }

    @Test
    public void testInvalids() throws UniversityWarning {
        Course c = simpleCourse();
        try {
            c.getLectureByIndex(5);
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        try {
            c.getLectureByIndex(-1);
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        try {
            c.removeLecture(null);
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        try {
            c.removeLecture(new Lecture());
            fail("Missed " + ErrorCodes.LECTURE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.LECTURE_NOT_FOUND, e.getMessage());
        }
        CoursesManager cm = new CoursesManager();
        try {
            cm.getCourseByIndex(0);
            fail("Missed " + ErrorCodes.COURSE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NOT_FOUND, e.getMessage());
        }
        cm.addCource("a", Discipline.Java6);
        try {
            cm.addCource("a", Discipline.Java7);
            fail("Missed " + ErrorCodes.COURSE_NAME_NOT_UNIQUE);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NAME_NOT_UNIQUE + "a", e.getMessage());
        }
        try {
            cm.removeCourse(null);
            fail("Missed " + ErrorCodes.COURSE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NOT_FOUND, e.getMessage());
        }
        try {
            cm.removeCourse(new Course());
            fail("Missed " + ErrorCodes.COURSE_NOT_FOUND);
        } catch (Exception e) {
            assertEquals(ErrorCodes.COURSE_NOT_FOUND, e.getMessage());
        }
    }
}
